package com.hevs.samplewebapp.server;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.google.appengine.api.datastore.Key;
import com.hevs.samplewebapp.server.entities.User;
import com.hevs.samplewebapp.server.service.UserService;
import com.hevs.samplewebapp.server.util.CredentialValidator;

/**
 * Custom
 * 
 * @author Arnaud Durand
 * @date 02.04.2012
 */
public abstract class SessionAuthHttpServlet extends HttpServlet {

	private static final long serialVersionUID = 3885366702609416438L;
	
	/**
	 * User service used for accessing users
	 */
	public static UserService userService;
	{
		userService = new UserService();
	}
	private int requiredCredentialLevel;
	
	private CredentialValidator specificValidation;
	
	private CredentialValidator genericValidation = new CredentialValidator() {
		@Override
		public boolean hasAccess(HttpServletRequest req,
				int requiredCredentialLevel) {
			HttpSession session = req.getSession(false);
			User authenticatedUser;
			try {
				authenticatedUser = userService.getUser((Key) session
						.getAttribute("userKey"));
			} catch (Exception e) {
				//unauthorized for inexistant session
				return false;
			}
			if (authenticatedUser.getCredentialLevel() < requiredCredentialLevel) {
				//unauthorized for insufficient credential level
				return false;
			}
			return true;
		}
	};

	/**
	 * Constructor
	 * 
	 * @param requiredCredentialLevel the lowest credential level than can access the servlet
	 */
	public SessionAuthHttpServlet(int requiredCredentialLevel) {
		this.requiredCredentialLevel = requiredCredentialLevel;
		this.specificValidation = new CredentialValidator() {
			@Override
			public boolean hasAccess(HttpServletRequest req,
					int requiredCredentialLevel) {
				return true;
			}
		};

	}

	/**
	 * @param req
	 * @param resp
	 * @throws ServletException
	 * @throws IOException
	 */
	protected void doSecureDelete(HttpServletRequest req,
			HttpServletResponse resp) throws ServletException, IOException {
		resp.sendError(405);
	}

	/**
	 * @param req
	 * @param resp
	 * @throws ServletException
	 * @throws IOException
	 */
	protected void doSecureGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		resp.sendError(405);
	}

	/**
	 * @param req
	 * @param resp
	 * @throws ServletException
	 * @throws IOException
	 */
	protected void doSecurePost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		resp.sendError(405);
	}

	/**
	 * @param req
	 * @param resp
	 * @throws ServletException
	 * @throws IOException
	 */
	protected void doSecurePut(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		resp.sendError(405);
	}

	/**
	 * @param genericCustomValidation
	 */
	public void setGenericCustomValidation(
			CredentialValidator genericCustomValidation) {
		this.specificValidation = genericCustomValidation;
	}

	@Override
	protected final void doDelete(HttpServletRequest req,
			HttpServletResponse resp) throws ServletException, IOException {
		if (!genericValidation.hasAccess(req, requiredCredentialLevel)
				|| !specificValidation.hasAccess(req,
						requiredCredentialLevel)) {
			resp.sendError(403);
			return;
		}
		doSecureDelete(req, resp);

	}

	@Override
	protected final void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		if (!genericValidation.hasAccess(req, requiredCredentialLevel)
				|| !specificValidation.hasAccess(req,
						requiredCredentialLevel)) {
			resp.sendError(403);
			return;
		}
		doSecureGet(req, resp);
	}

	@Override
	protected final void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		if (!genericValidation.hasAccess(req, requiredCredentialLevel)
				|| !specificValidation.hasAccess(req,
						requiredCredentialLevel)) {
			resp.sendError(403);
			return;
		}
		doSecurePost(req, resp);

	}

	@Override
	protected void doPut(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		if (!genericValidation.hasAccess(req, requiredCredentialLevel)
				|| !specificValidation.hasAccess(req,
						requiredCredentialLevel)) {
			resp.sendError(403);
			return;
		}
		doSecurePut(req, resp);

	}

}
